Technical Note TN2071
Porting Command Line UNIX Tools to Mac OS X
目次

はじめに

この記事では、Mac OS X[1] の内側、および、UNIX[2] のコマンドラインベースのアプリケーションを Mac OS X に移植するデベロッパのための情報を提供します。

この記事は、従来の UNIX 開発環境におけるプログラミングに慣れているデベロッパを対象としています。また、この記事は UNIX の一般ユーザを対象に書かれたものではありません。

この記事では、Mac OS X オペレーティングシステムを理解する上で必要となる背景知識について説明します。また、設計時に行われたいくつかの判断についても触れ、Mac OS X に UNIX アプリケーションを移植する際に考慮すべき主だった事柄のいくつかをリストにして、検討します。さらに、移植アプリケーションに追加できる従来の UNIX アプリケーションでは利用できない Mac OS X の高度な機能のいくつかを示します。この記事は、チュートリアルではなく概要です。多くの点で Inside Mac OS X: System Overview[3] の姉妹編とも言える記事ですが、UNIX デベロッパを主要読者として想定しています。

この記事は、UNIX アプリケーションの Mac OS X 10.2.x への移植に関する個別の疑問に対する答えはもちろん、プラットフォーム全体についての疑問に対する答えも提供します。

Mac OS X でサポートされていない API の一覧が、推奨される代替案とともに記載されています。この記事ではまた、アプリケーションの移植作業をより早く、簡単に、効率的に行うためのいくつかのヒントについても説明します。

[2003 年 9 月 3 日]


注記: オープンソースアプリケーションの Mac OS X への移植を考えている場合には、OpenDarwin[4] と Fink[5] のサイトを参照して、移植を考えているアプリケーションが既に移植されていないかどうかを調査する必要があります。Mac OS X で利用できるオープンソースアプリケーションの大きなレポジトリを一元的に管理できるように、これらのサイトとの連携も考慮する必要があります。

関連情報

アップルのデベロッパ Web サイト [6] でデベロッパを対象としたドキュメントを見つけることができます。このサイトには、Mac OS X 上の開発に関連したリファレンス、概念を説明するドキュメント、チュートリアルが揃っています。 Mac OS X Developer Tools[7] CD には、ドキュメントのスナップショットが収録されています。これらは、/Developer/Documentation にインストールされます。Mac OS X Developer Tools には、マニュアルのページも収録されています。

アップルは数多くのメーリングリストを主催しています。これらのメーリングリストは一般公開されており、lists.apple.com で購読の申し込みと検索が行えます。unix-porting[8] のメーリングリストはたいへんお薦めです。また、darwin-development[9] と darwinos-users[10] のメーリングリストも十分に役に立つ情報を提供しますが、特に移植作業に限定されたものではありません。これらのリストの アーカイブ [11] も、同様に、このメーリングリストの Web サイトで利用できます。

アップル自体のリソースに加えて、外部のリソースも数多く存在します。お薦めする Web サイトは 2 つ、オライリー社の Mac DevCenter[12] と Stepwise[13] です。

Mac OS X の展開

Berkeley Software Distribution (BSD)

Mac OS X の歴史の一部分は、70 年代初頭の Berkeley Software Distributions (BSD)[14] UNIX に遡ります。厳密に言えば、Mac OS X の一部は BSD 4.4 Lite をベースにしています。システムレベルでは、BSD スタイルの UNIX システムと互換性を保つための数多くの配慮が設計に盛り込まれています。ライブラリおよびユーティリティの大部分は FreeBSD[15] に由来するものですが、NetBSD[16] を由来とするものもあります。将来の開発を見据え、Mac OS X では BSD 技術の参照コードベースとして FreeBSD を採用しています。現在、すべての BSD ツールおよびライブラリを FreeBSD の安定ブランチにより密接に同期させるべく作業を継続中です。

Mach

Mac OS X は、オペレーティングシステムの基礎レベルの大部分について BSD が寄与していますが、Mach が大きく寄与している部分もあります。Mac OS X のカーネルの設計理念は、カーネギーメロン大学の Mach Project[17] から多大な影響を受けています。アドレス空間がカーネルの BSD 部分と I/O Kit によって共有されているため、Mac OS X のカーネルはマイクロカーネルの純粋な実装ではありません。

Mac OS X と Darwin

Darwin[18] という用語は、Mac OS X を指す言葉としてよく用いられます。実のところ、Mac OS X という言葉がほとんど出ない場合もあります。Mac OS X と Darwin の違い、つまりこの 2 つの相互関係および相違点を理解することが重要です。

Darwin は、Mac OS X オペレーティングシステムの中核を成しています。Darwin は、独立したオペレーティングシステムとしてスタンドアロンでも機能しますが、Mac OS X を総体として見た場合に利用できる機能の一部しか含まれていません。

高度な拡張

ネットワーククライアントツールおよびシステムサービスのような基本となる UNIX の長所に加え、Mac OS X では、デベロッパが簡単に利用できる一連の高度なテクノロジーが提供されます。
  • Quartz Extreme[19] - Mac OS X の新しい 2D 描画 API は、Postscript/PDF 描画モデルをベースとしており、トランスペアレンシー(透明度)およびアンチエイリアシング、複数の色空間、PDF の入出力、組み込みの ICC カラーマネジメントを完全にサポートしています。
  • OpenGL[20] - Mac OS X は、nVidia および ATI のグラフィックスアダプタによってアクセラレートされた業界標準の OpenGL 3D グラフィックスアーキテクチャをサポートします。
  • QuickTime[21] - デベロッパは、Mac OS X を介して、Flash 4 のサポート、Cubic VR、RTP/RTSP ビデオストリーミング、MPEG サポート、その他の機能を含む QuickTime の完全なマルチメディアアーキテクチャにアクセスできます。
  • 国際化対応テクノロジー [22] - デベロッパは、Mac OS X の Unicode 対応サポートを使用して、アプリケーションを短期間で簡単にダブルバイトの言語にローカライズすることができます。
  • CUPS[23] - Common UNIX Printing System(「CUPS」)は、UNIX 環境用のクロスプラットフォームのオープンソースプリントソリューションであり、Darwin および Mac OS X のポータブルプリントレイヤとして使用されます。CUPS は、Internet Printing Protocol をベースとしており、PostScript プリンタとラスタプリンタ向けに、System V および BSD の両方のコマンドラインプリントサービスを提供します。

一般的な移植

移植は、あるプラットフォームに合わせて作られたソフトウェアを別のプラットフォームに移行する作業です。新しい環境で実行できるように、ソフトウェアの部分的な書き換えや、ソースコードのわずかな修正が必要になることもあります。

なぜ移植なのか

熟練の UNIX デベロッパならば、UNIX ベースの 2 つのオペレーティングシステムがどんなに似ていても、システム同士の違いを生む差異が細部に必ず存在することを認識しています。UNIX ベースのシステムは数多くの系統が存在しますが、これらのすべてが同じ一連のツールとアーキテクチャを提供するわけではありません。

このセクションでは、Mac OS X 用にコードベースをコンパイルすることになった場合に覚えておくべきいくつかの重要な領域に焦点を当てます。ここでは、Mac OS X においてコードの各所をリンクする方法について解説するとともに、コンパイラフラグの重要な詳細に注目します。これらのトピックの多くは、それぞれの説明で示す他の情報源でさらに詳しく取り上げられています。

Mac OS X へのコードの基本的な移植を開始する前に、その作業に必要な一連のツールを持っていることを確認する必要があります。また、標準で利用できるものとできないものを認識しておくことも必要です。

コンパイラの選択

Mac OS X 10.2.x には、2 つの異なるコンパイラと、それらに対応する一連のツールが含まれています。標準コンパイラは、gcc 3.1 をベースとします。gcc 2.95.2 をベースとする第 2 のコンパイラも用意されています。

将来のツール群は gcc バージョン 3.1 以降をベースとするようになるので、必ず gcc 3.1 を使用してソフトウェアのコンパイルを行うようにする必要があります。

コンパイラに起因すると考えられる問題に遭遇した場合は、コマンド sudo gcc_select 2 により、標準のコンパイラを gcc 2.95.2 に変更します。 sudo gcc_select 3 と入力することによって、いつでも元のコンパイラに戻すことができます。ただし、これは最後の手段と考える必要があります。可能な限り、コンパイラフラグを変えてみることによって、gcc 3.1 でアプリケーションをコンパイルできるようにするべきです。

注記: システムによっては、標準のコンパイラが cc である場合がありますが、Mac OS X 上では、ccgcc は同じコンパイラです。

アップルは、標準の UNIX 開発ツールに加え、Project Builder (PB)[24] および Interface Builder (IB)[25] という独自の GUI 開発環境も提供しています。これらのツールにより、Mac OS X での開発がより簡単になるので、開発ツールにかかわる問題に煩わされずにコードに集中できます。これらのツールの使用を強くお薦めします。これらのツールは無償であり、Mac OS X を構成する一部として提供されています。

注記: 開発ツールは、Mac OS X の標準インストールではインストールされません。このツールは、独立の CD-ROM またはディスクイメージとして提供されています。そのため、このツールは個別にインストールする必要があります。このツールのディスクイメージは、アップル開発ツール [26] Web サイトからもダウンロードできます。

コンパイラフラグ

以下は、知っておくべき一般的なコンパイラフラグの一覧です。

-no-cpp-precomp
標準では、アップルの GCC は、プリコンパイル済ヘッダをサポートする cpp-precomp と呼ばれる専用のプリプロセッサを使って C および Objective-C のプリプロセスを行います。このプリプロセッサは、GCC がサポートするすべての要素を処理できるわけではありません。 -no-cpp-precomp フラグを使用することによって、Mac OS X のプリプロセッサを無効にして、GNU プリプロセッサを動作させることができます。ヘッダ(プリコンパイル済またはそうでないもの)に関連するエラーメッセージが発生した場合、まずはこのフラグを試すとよいでしょう。
注記: Mac OS X 開発ツールの以前のバージョンでは、-traditional-cpp が推奨されていました。このフラグは、現在のバージョンでも動作しますが、より正確なフラグとして -no-cpp-precomp の使用が推奨されており、現在はこちらを使用するべきです。
-ObjC、-ObjC++
これらのフラグは、実質的に -x objective-c および -x objective-c++ と似ていますが、既にソースファイルとして指定されているファイルのコンパイラの選択にだけ影響します。
-faltivec
モトローラの AltiVec PIM で定義されている AltiVec 言語拡張を有効にします。これには、(コンテキスト依存の)キーワードである vectorpixel の認識、vec_add のような組み込み関数の定義、そのほかの拡張が含まれます。
注記: -maltivec オプションとは異なり、この拡張機能は、特別なヘッダファイルのインクルードをまったく必要としません。
-fconstant-cfstrings
リテラル文字列を対象に、特別な組み込み __builtin__CFStringMakeConstantString が呼び出されたときに、CoreFoundation 型の文字列定数が自動的に生成されるようにします。
-fpascal-strings
Pascal 型の文字列リテラルを作成できるようにします。
-fcoalesce
重複する関数とデータを一本化します。リンカは、1 つを残して他のすべてを破棄することによって空間を節約します。この設定は、標準で有効です。
-fweak-coalesced
一本化される項目について OS X の新しい weak_definitions セクションの属性を使用します。任意の数の弱い定義に優先して 1 つの通常の定義がリンカによって選ばれます。
-fno-rtti
C++ のランタイム型識別機能(dynamic_casttypeid)での使用を目的とした、仮想関数を持つすべてのクラスに関する情報の生成を無効にします。言語のその部分を使用しない場合には、このフラグを用いることによって空間を節約できます。例外処理では同じ情報が使用されますが、その場合には情報が必要に応じて生成されます。
-shared
このオプションは、Mac OS X ではサポートされません。代わりにリンカ用の -dynamic オプションを使用します。
--dump-pch name
ほかの引数をすべて処理してから、name に指定された名前のディレクトリにコンパイラの状態をダンプします。これは、プリコンパイル済のヘッダを作成するのに便利です。
--load-pch name
name に指定された名前のディレクトリからコンパイラの状態を復元した後でほかの引数を処理します。この最終的な効果は -include に似ていますが、それよりも早く効果を発揮します。
たとえば、「myprefix.c」ファイルが、プログラムのすべてのファイルに役立ついくつかのヘッダをインクルードしている場合には、次のように指定できます。
gcc --dump-pch foo -c myprefix.c
gcc --load-pch foo myfile1.c
gcc --load-pch foo myfile2.c
gcc --load-pch foo myfile2.c
...
-findirect-virtual-calls
仮想関数を、直接呼び出すのではなく、必ず vtable を経由して呼び出します。
-fapple-kext
vtable、デストラクタ、その他の実装機能の詳細部分を変更して、GCC 2.95 ABI の動作に近づけます。このフラグにより、古いコンパイラを使用してビルドした Darwin カーネルで、カーネル拡張機能を読み込むことができます。
-fcoalesce-templates
インスタンス化されたテンプレートに「一本化の対象」として印を付けます。リンカは 1 つを除いてすべてを破棄することで空間を節約します。
-Wpragma-once
#pragma once の使用についての警告の発行を一度だけに限定します。
-Wextra-tokens
プリプロセッサ命令の末尾に余分なトークンがある場合に警告を発行します。
-Wmost
このフラグは -Wall -Wno-parentheses に相当します。
-Wnewline-eof
末尾に改行がないファイルについての警告を発行します。
-Wno-altivec-long-deprecated
AltiVec のデータ型において廃止された long キーワードの使用についての警告を発行しないようにします。
-Wno-long-double
long double 型が使用されている場合の警告を抑止します。
-dependency-file
-M または -MM とともに使用した場合は、依存関係の書き込み先ファイルを指定します。 -MF スイッチが指定されていない場合、プリプロセッサは、本来プリプロセス後の出力先となる場所にルールを送ります。
-no-c++filt
標準では、リンカによる診断出力はすべて c++filt を経由してパイプ処理されます。このオプションは、その処理を抑止します。

-nostdlib-nodefaultlibs によってバイパスされる標準ライブラリの 1 つが libgcc.a です。 libgcc.a は、特定のマシンにおける不足を補うため、あるいは、一部の言語の特別なニーズに対応するために、GCC によって使用される内部サブルーチンのライブラリです。

ほとんどの場合、ほかの標準ライブラリを避けたいときでも、libgcc.a だけは必要です。つまり、-nostdlib または -nodefaultlibs を指定するときには、通常、-lgcc も指定する必要があります。この指定により、内部の GCC ライブラリのサブルーチン(たとえば、C++ のコンストラクタの呼び出しが確実に行われるようにする __main など)に対する未解決の参照がないことが確実となります。
-malign-mac68k, -malign-power, -malign-natural
オプション -malign-mac68k は、m68k のコンパイラ出力と互換性を持たせるために、構造体フィールドを 2 バイトの境界に合わせます。オプション -malign-power は、PowerPC 用の標準アラインメントモードです。オプション -malign-natural は、double などの長いデータ型を本来の境界に揃える PowerPC アラインメントの拡張です。
-mdynamic-no-pic
Mac OS X システム上で、コードを再配置できないようにする一方で、外部参照は再配置できるようにコンパイルします。結果として生成されるコードはアプリケーションに適していますが、共有ライブラリには適していません。
-mlong-branch
Mac OS X システム上で、呼び出し時に 32 ビットの呼び出し先アドレスを使用するように呼び出しをコンパイルします。これは、カーネルのアドレス空間内の任意の場所に読み込まれるカーネル拡張をサポートするためのものです。

共有ライブラリ、バンドル、リンカ

アップルは、Mac OS X の拡張機能をサポートするため、独自のリンカを開発しました。
注記: Mac OS X はシングルパスのリンカを使用します。フレームワークおよびライブラリのオプションは、必ずオブジェクト(「.o」)ファイルの後に指定してください。アップルのリンカの詳細については、マニュアルの ld のページを参照してください。

Mac OS X のカーネルは、ほかの UNIX システムとは異なる機構をサポートすることによって共有ライブラリを処理します。共有ライブラリ、および、ほかのシステムではロード可能モジュールとして知られるバンドルの実装が異なります。アプリケーションが共有ライブラリを使用する場合には、特別な手順を踏む必要があります。Linux[27] や Solaris[28] をはじめとする他のほとんどの UNIX システムでは、バンドルと共有ライブラリが同じように扱われますが、Mac OS X では扱われ方が異なります。

Mac OS X に移植されるアプリケーションの多くは、Mac OS X でサポートされない dlopendlgetsdlclose のような API を使用しています。以下に、これらの API と、Mac OS X へのアプリケーションの移植を可能にする、代わりの API または代替案を示します。

ダイナミックライブラリおよびバンドルをアップルの dyld 形式に移行することに決めた場合は、以下に代替手段を示すので、単純に関数を入れ替えるのではなく、必ず各種のデータ型を処理できるようにコードを適切に調整するようにしてください。

dlopen
既存の dyld API の NSCreateObjectFileImageFromFile を使って dlopen の動作を自身でエミュレートして、NSObjectFileImage を作成したり、返したりできます。この NSObjectFileImage は、_dyld_debug_task_from_core を使ってタスクに読み込んで、ロードされたライブラリと、リンクされたモジュールを知ることができます。



たとえば、次のようなコードがあったとします。
const char *filename = argv[1];
void *handle = dlopen(filename, RTLD_NOW);
これを次のコードで差し替える必要があります。
const char *filename = argv[1];
NSObjectFileImage *fileImage;
NSModule handle;
NSObjectFileImageReturnCode *returnCode =
NSCreateObjectFileImageFromFile(filename, &fileImage);

if(returnCode == NSObjectFileImageSuccess)
{
    handle = NSLinkModule(fileImage,filename, 
        NSLINKMODULE_OPTION_RETURN_ON_ERROR
      | NSLINKMODULE_OPTION_PRIVATE);
    NSDestroyObjectFileImage(fileImage);
    if (handle) {
  /* コードで実行するその他の処理*
dlclose
dlclose は、dlopen によって得られたハンドルの関連付けを解除します。これと同じ効果を NSCreateObjectFileImageFromFile で得るには、NSDestroyObjectFileImage を使用します。この API は、パラメータとして NSObjectFileImage を受け取ります。これは、NSCreateObjectFileImageFromFile API によって作成されます。

たとえば、次のようなコードがあったとします。
int result = dlclose(handle);
これを次のコードで差し替える必要があります。
DYLD_BOOL result = NSUnlinkModule(handle, 0);
dlopen を呼び出した後に dlclose を呼び出す限り、この移行は簡単です。

dlerror
NSLinkModule のオプション NSLINKMODULE_OPTION_RETURN_ON_ERROR を使用して、モジュールのロード中にエラーが発生したかどうかを知ることができます。エラーが発生していた場合には、NSLinkEditError API を使用してエラー情報を取得できます。

たとえば、次のようなコードがあったとします。
printf("%s¥n", dlerror());
これを次のコードで差し替える必要があります。
int * null;
NSLinkEditErrors* c;
const char ** errorMsg;
NSLinkEditError(c, null, (const char**)lpLibFileName, errorMsg);

printf("%s¥n", errorMsg);
dlsym
API NSAddressOfSymbol は、dlsym と同じ機能を持っています。 NSAddressOfSymbol は、void * である NSSymbol を受け取り、指定されたシンボルのアドレスを返します。

注記: NSAddressOfSymbol は、dlsym とは異なり、第 2 パラメータを受け取りません。
たとえば、次のようなコードがあったとします。
void *address = dlsym(handle, symbol);
これを次のコードで差し替える必要があります。
NSSymbol nssym = NSLookupSymbolInModule(handle, symbol);
void *address = NSAddressOfSymbol(nssym);

2 レベルの名前空間とフラットな名前空間

2 レベルの名前空間とフラットな名前空間は、ダイナミックライブラリのシンボルに対する参照を解決して、特定のダイナミックライブラリにおける定義に帰着する方法を指します。

2 レベルの名前空間を使ってビルドされたイメージを使用するプログラムでは、プログラムの個々のイメージで、異なるグローバルシンボルについて同じ名前が用いられている場合があります(Mac OS X 10.1 以降では標準です)。

プログラムが使用するイメージがすべてフラットな名前空間を使用するものである場合、プログラムのすべてのイメージで、それぞれのグローバルシンボル名に対してグローバルシンボルが 1 つだけ使用されます。

-twolevel_namespace
2 レベルの名前空間を使用するイメージとして出力をビルドするよう指定します。このオプションは、環境変数 LD_TWOLEVEL_NAMESPACE を設定して指定することもできます。
注記: Use -multiply_defined suppress to stop the warnings regarding multiply defined symbols.
-flat_namespace
フラットな名前空間を使用するイメージとして出力をビルドすることを指定します。これは、Mac OS X 10.0 の標準の設定でした。
-force_flat_namespace
すべてのダイナミックライブラリをフラットな名前空間のイメージとして扱うように実行可能ファイル出力をビルド、および、実行するように指定します。これは、プログラムの実行時に、すべてのダイナミックリンクライブラリをフラットな名前空間のイメージとして扱うようにダイナミックリンクエディタに認識させるために、実行可能ファイルにマークを付けます。

多重定義のシンボル

作成される出力ファイルにリンクされたオブジェクトファイルに多重定義されたシンボルがある場合、必ず多重定義シンボルエラーが発生します。

-multiply_defined treatment
-twolevel_namespace が有効なときの、ダイナミックライブラリの多重定義シンボルの取り扱い方法を指定します。treatment の部分には、 errorwarning、または suppress を指定できます。これらは、-twolevel_namespace が有効な場合に、ダイナミックライブラリにおける多重定義シンボルを エラー(error)または警告(warning)の対象として扱うか、あるいは、多重定義シンボルのチェックを抑止(suppress)するかを示します。標準では、-twolevel_namespace が有効な場合には、ダイナミックライブラリにおける多重定義シンボルは警告の対象として扱われます。
-multiply_defined_unused treatment
-twolevel_namespace が有効なときの、ダイナミックライブラリの未使用の多重定義シンボルの取り扱い方法を指定します。未使用の多重定義シンボルとは、出力において定義されるシンボルが、出力のリンク先のダイナミックライブラリでも定義されているけれども、そのシンボルが出力のどの参照によっても使用されていないものを指します。treatment の部分には、 errorwarning、または suppress を指定できます。未使用の多重定義シンボルの標準の取り扱い方法はメッセージを抑止することです。

ヘッダファイルとフレームワーク

標準のヘッダファイルは、/usr/include にあります。フレームワークは共有ライブラリに似ており、ヘッダ、ライブラリ、その他を 1 つのフォルダに寄せ集めたものです。各フレームワークは、別々の場所に記憶されているため、それぞれ個別に検索する必要があります。

アップルが提供するフレームワークは、/System/Library/Frameworks/ にあります。それぞれのディレクトリには Headers という名前のディレクトリがあり、そこに共有のヘッダファイルがあります。各ヘッダファイルには、いくつかの API が含まれています。

自分のフレームワークは、フレームワークを公開するかどうかに応じて、/Network/Library/Framework/Library/Framework、または ‾/Library/Frameworks などにインストールできます。

フレームワークのヘッダファイルの 1 つで宣言されている API を使いたい場合は、コンパイル時にフラグとして -framework API名 -framework API名2 -framework API名3 ... を指定できます。Mac OS X はシングルパスのリンカを使用するので、このフラグを必ず「.o」ファイルの後に指定するようにします。

たとえば、Address Book API を使用するには、次のようにします。
-(int)beginLoadingImageDataForClient:(id )client
そして、このヘッダファイルをコードに追加する必要があります。
#include <AddressBook/ABImageLoading.h>

定義済みマクロ

アップルデベロッパ GNU C Preprocessor ドキュメント [43] で規定されているように、以下のマクロが Mac OS X であらかじめ定義されています。

__OBJC__
このマクロは、Objective-C の .m ファイルまたは Objective-C++ の .mm ファイルのコンパイル時や、-ObjC または -ObjC++ フラグを使用してファイル拡張を無効にした場合に定義済みとなります。
__ASSEMBLER__
このマクロは、.s ファイルをコンパイルするときに定義済みとなります。
__NATURAL_ALIGNMENT__
このマクロは、自然アラインメントを使用するシステムにおいて定義済みとなります。自然アラインメントを使用する場合、intsizeof(int) の境界に合わせて、また short int は sizeof(short) バウンダリに合わせて、という具合にアラインメントが行われます。PowerPC、SPARC、HPPA 用のコードをコンパイルする場合には、これらは標準で定義済みとなります。-malign-mac68k コンパイラスイッチを用いる場合は、定義済みになりません。
__STRICT_BSD__
このマクロは、GNU C の起動時に -bsd スイッチが指定された場合に定義済みとなります。
__MACH__
このマクロは、Mach システムコールがサポートされている場合に定義済みとなります。
__APPLE__
このマクロは、すべてのアップルコンピュータで定義済みとなります。
__APPLE_CC__
このマクロは、コンパイラのバージョン番号を示す整数に設定されます。これにより、たとえば、GCC の同じバージョンをベースとするけれども、バグ修正や機能が異なる 2 つのコンパイラを区別できます。値が大きいほうが新しいコンパイラを示します。
__BIG_ENDIAN__
このマクロは、ターゲットアーキテクチャを最上位バイト指定として設定します。詳細については、「エンディアンの問題」のセクションを参照してください。
注記: コードの特定のセクションが Mac OS X システム上でコンパイラされるように定義するには、__MACH__ マクロとともに __APPLE__ を使用してセクションを定義する必要があります。マクロ __UNIX__ は、Mac OS X ではサポートされていません。

エンディアンの問題

メモリ内のマルチバイトのデータフィールドを参照する方法は 2 つあります。1 つはビッグエンディアンとして知られており、最上位バイト (MSB) を指すフィールドアドレスで構成されます。これに対して、もう 1 つはリトルエンディアンとして知られており、最下位バイト (LSB) を指すフィールドアドレスで構成されます。

アップルではビッグエンディアン (MSB) のアドレス指定を採用していますが、ほかのシステムの中にはリトルエンディアン (LSB) を使用するものもあります。バイト反転のためのユーティリティ関数は、「endian.h」ヘッダファイルにあります。

スレッドの処理

Mac OS X に移植される UNIX アプリケーションは、おそらく POSIX スレッドを使用します。Mac OS X におけるスレッドの機能を理解するには、Mac OS X Threading Architectures[29] のドキュメントを参照してください。

Mac OS 10.2.x では POSIX API のサポートが強化されているため、Mac OS X への移植を行う大多数のデベロッパは移行が楽になります。サポートされる POSIX スレッディング API は「pthread.h」に含まれています。

このセクションでは、POSIX スレッド関数を以下のグループに分けます。

  • スレッドルーチン
  • アトリビュートオブジェクトルーチン
  • Mutex ルーチン
  • 状態変数ルーチン
  • 読み取り/書き込みロックルーチン
  • スレッド単位コンテキストルーチン
  • クリーンアップルーチン

Mac OS X 10.1.x への UNIX アプリケーションの移植を行っているデベロッパ、または移植を計画しているデベロッパに対する注意点として、pthread_kill をはじめとする pthread API が Mac OS X 10.2 に追加され、「pthread.h」と「signal.h」に含まれています。「pthread_kill」は、Mac OS X 10.2 以前の Mac OS X ではサポートされていませんでした。

国際化

ワイドキャラクタ wchar は、Mac OS X ではサポートされていません。その代わりに、CFStringGetSystemEncodingCFStringCreateCopyCFStringCreateMutable など、CoreFoundation の「CFString.h」に含まれている API を使う必要があります。サポートされている API の一覧については「CFString.h」を参照してください。

Mac OS X では、Unicode に基づく文字列を使用して、文字列を国際化することができます。 Unicode[30] 規格は、国際標準化団体である Unicode Consortium[31] によって定められています。

Mac OS X では、次のエンコーディングが利用できます。
kCFStringEncodingMacRoman
kCFStringEncodingWindowsLatin1
kCFStringEncodingISOLatin1
kCFStringEncodingNextStepLatin
kCFStringEncodingASCII
kCFStringEncodingUnicode
kCFStringEncodingUTF8
kCFStringEncodingNonLossyASCII

CoreFoundation の StringServices の能力を十分に理解するには、参考文献 [32] を参照してください。

デバイスドライバ

Mac OS X のデバイスドライバの実装は、ほかのシステムとは異なっています。デバイスドライバを使用するアプリケーションを移植する場合は、Mac OS X 対応の新たなデバイスドライバを作成する必要があります。

新しいデバイスドライバを作成するには、I/O Kit を使う必要があります。I/O Kit は、システムフレームワーク、ライブラリ、ツール、および Mac OS X でのデバイスドライバの作成に必要なそのほかのリソースを集めたものです。I/O Kit デバイスドライバは特別なタイプのカーネル拡張(KEXT)であり、これによってカーネルによるデバイスの処理が可能となります。

多くの場合、デバイスには userland プロセスから間接的にアクセスできるため、カーネルドライバを記述する必要はありません。間接的にアクセスしたほうが、可能ならいつでもコードをカーネルの外部に置くことができるため、この方法をお薦めします。

Project Builder を使用してデバイスドライバを作成する方法については、手順を説明している各種のドキュメント [33]を参照してください。

オーディオ

オーディオアプリケーションを移植するには、Mac OS X で使用されている基盤オーディオアーキテクチャを理解した上で、Core Audio API を使ってコードを書き換える必要があります。

Linux の「soundcard.h」や Solaris の「audioio.h」を使用するアプリケーションを移植しているのであれば、よく似た API が「CoreAudio.h」にあります。Mac OS X 10.2.x では Core Audio アーキテクチャが強化されており、Core Audio Framework を使用するだけで、単純な機能なら簡単に実現できます。しかし、ハードウェアや入出力を処理する下位レベルの API を使用するアプリケーションの場合、いくつかのフレームワークがかかわるアーキテクチャの全体を理解する必要があります。

Core Audio Developer Documentation[34] を読んでからアプリケーションの移植に取り掛かることを強くお薦めします。

ビデオ

ビデオアプリケーションを移植する場合は、QuickTime フレームワークに含まれている QuickTime API を使う必要があります。QuickTime フレームワークは、自動的にオーディオ API の一部を呼び出すことによって、ビデオのオーディオが、ビデオとともに移植されることを保証します。QuickTime とその API にあまり詳しくない場合は、QuickTime Developer Documentation[35] を参照してください。

認証サービス

認証サービスを使用するアプリケーションを移植する場合は、Security Services[36] フレームワークの API を使う必要があります。コマンドラインレベルで認証 API を使用すると、API は GUI を無視し、コマンドラインでパスワードの入力を求めます。

auth_destroyauthnone_createauthunix_createauthunix_create_default など、Linux でサポートされる認証ハンドルは、Mac OS X では rpc を通じてサポートされます。詳しくは、マニュアルの rpc のページを参照してください。

Mac OS X のアクセス制御の使用方法を理解するには、Authorization Services[37] のドキュメントを参照してください。また、認証サービス API を正しく使う方法を示す認証用サンプルコード [38] を参照してください。

ヘッダファイル

alloc.h
このファイルは Mac OS X に存在しませんが、その機能は存在します。単純に「stdlib.h」をインクルードするか、以下に示すコードを使用して、このヘッダファイルを独自に作成できます。
#ifndef _ALLOCA_H

#undef  __alloca

/* ここで内部インタフェースを定義する */
extern void *__alloca (size_t __size);

#ifdef  __GNUC__
# define __alloca(size) __builtin_alloca (size)
#endif /* GCC.  */

#endif
ftw.h
API ftw は、ディレクトリ階層を渡り歩き、関数を呼び出して各ファイルの情報を取得します。Mac OS X では、API fts_open を使用してファイル階層のハンドルを取得し、fts_read を使用して各ファイルの情報を取得します。また、fts_children を使用して、ディレクトリにあるファイルに関する情報を含んだ構造体のリストに対するリンクを取得します。

Mac OS X では、代わりに「ftw.h」にとてもよく似た fts を使います。ただし、「fts.h」には ftw に似た関数がありません。fts_openfts_childrenfts_close を使用してファイルの渡り歩きを実装する必要があります。 たとえば、「fts.h」を使って /usr/include に格納されている各ファイルの詳細を取得するには、以下のようなコードになります。
/* argv[3] を通じてパス "/usr/include" が渡されていると仮定する */

fileStruct = fts_open(&argv[3], FTS_COMFOLLOW, 0);
dirList = fts_children(fileStruct, FTS_NAMEONLY);

do
{
 fileInfo = fts_read(dirList->fts_pointer);

 /* この時点で fts_read によって返された */
 /* FTSENT から情報を引き出すことができる */

 fileStruct = fts_open(dirList->fts_link->fts_name, 
FTS_PHYSICAL, (void *)result);

}while (dirList->fts_link != NULL);

ftsResult = fts_close(fileStruct);
構造体 FTSENTFTS と、コードで使用されるマクロを説明については、マニュアルの fts のページを参照してください。上記のサンプルコードは、極めて単純化したファイルの渡り歩きを示しています。たとえば、検索対象ディレクトリにサブディレクトリがある可能性は考慮されていません。
getopt.h
サポートされていませんので、「unistd.h」を使用します。
lcrypt.h
サポートされていませんので、「unistd.h」を使用します。
malloc.h
サポートされていませんので、「stdlib.h」を使用します。
mm.h
このヘッダは、Linux ではメモリマッピング用にサポートされますが、Max OS X ではサポートされません。Mac OS X では、メモリへのファイルマッピング用に mmap を使うことができます。デバイスをマップしたい場合は、I/O Kit を使用します。
module.h
モジュールとシンボルを処理するインタフェースとして NSModule を使います。 NSModule は、<mach-o/dyld.h> ヘッダファイルで void * と定義されているにすぎません。API NSLinkModule を使用します。
msg.h
メッセージキューの組み込み方法の詳細については、テクニカルノート 1071[39] を参照してください。msggetmsgsnd、msgrcv、msgctl など、「msg.h」に実装されている API もサポートされていません。上述のテクニカルノートは、これらの関数からの機能の組み込みに役立ちます。
nl_types.h
CoreFoundation[40] のローカライズされた文字列 [41] を使用して API にアクセスします。
ptms.h
このヘッダファイルは Linux にはありますが、Mac OS X にはありません。ただし、pty は Mac OS X においてサポートされています。その実装工程は、Linux とはかなり異なります。pty の実装の全体説明については、マニュアルの pty のページを参照してください。
stream.h
このヘッダファイルはシステムに存在しません。ファイルのストリーミングには、「iostream.h」を使います。
stropts.h
サポートされていません。
swapctl.h
Mac OS X では、このヘッダファイルはサポートされていません。ヘッダファイル「swap.h」を使って、スワップ機能を組み込むことができます。この「swap.h」ヘッダファイルには、スワップのチューニング制御に使用できる数多くの API が含まれています。
termio.h
このヘッダファイルは時代遅れとなり、POSIX 規格の一部である temios.h の使用が優先されます。これら 2 つのヘッダファイルはとてもよく似ていますが、「termios.h」は「termio.h」と同じヘッダファイルをインクルードしません。したがって、「termios.h」を直接調べて、自分のアプリケーションに必要な処理が実行されることを確認する必要があります。
utmpx.h
サポートされないので、代わりに「utmp.h」を使用します。
values.h
サポートされないので、「limits.h」を使用します。
wchar.h
サポートされないので、CoreFoundation[40] のローカライズされた文字列の API を使用します。
wordexp.h
Mac OS X ではサポートされません。

関数

btowc、wctob
Mac OS X では現在のところ wchar はサポートされていません。wchar の代わりに、CoreFoundation[40] フレームワークの一部である CFString を使用することにより国際化文字列を処理します。CoreFoundation の「CFString.h」で利用できる API の例としては、CFStringGetSystemEncondingCFStringCreateCopyCFStringCreateMutable などがあります。サポートされる全 API のリストについては、「CFString.h」を参照してください。
catopen、catgets、catclose
nl_types.h」がサポートされていないため、これらの関数もサポートされません。これらの関数は、ローカライズされた文字列に対するアクセスを可能にします。Mac OS X には、これに直接対応するものがありません。一般的に、コマンドラインのツールをはじめとした Mac OS X のプログラムでは、ローカライズされたリソースに CoreFoundation を使用してアクセスします。たとえば、CFBundleCopyLocalizedString[42] を参照してください。
crypt
The crypt 関数は、NBS Data Encryption Standard(DES)に基づいてパスワードの暗号化を実行します。暗号鍵の探索の試みを阻止するために、一部コードが追加されています。

この関数が受け取る引数と返す値の型は、Linux の crypt と同じです。crypt 関数の Mac OS X のバージョンの動作は、128 ビット定数ではなく 64 ビット定数として暗号化する点を除けば、Linux バージョンにたいへんよく似ています。この関数は、「lcrypt.h」ではなく、「unistd.h」ヘッダファイルにあります。
注記: リンカのフラグ -lcrypt は Mac OS X ではサポートされていません。
dysize
この API は Mac OS X ではサポートされていません。うるう年の計算は、以下の計算式に基づいています。
(year) %4 == 0 && ((year) %100 != 0 || (year) % 400 == 0)
このコードを使ってこの機能を組み込むか、「time.h」にある既存の API のどれかを使って同様の機能を実現することができます。
ecvt、fcvt
Mac OS X でサポートされていません。代わりに、sprintf または snprintf を使用します。
fcloseall
この関数は fclose に対する拡張です。Mac OS X では fclose はサポートされていますが、fcloseall はサポートされていません。 fclose を使用して fcloseall を実装することができます。 fileNamePtr[i] という FILE *streams の配列があると仮定して、次のように実装できます。
for(i = 0; i < MAXSTREAMS; i++)
     fclose(fileNamePtr[i]);
getmntent、setmntent、addmntent、endmntent、hasmntopt
Mac OS X では、POSIX 規格を使用してファイル記述子を管理します。これらの関数はサポートされていません。
poll
この API は Mac OS X ではサポートされていません。代わりに select 関数を使用します。 select 関数は、poll と同様に同期的な I/O の多重化を行います。この API は、ヘッダファイル <sys/types.h>、<sys/time.h>、<unistd.h> にあります。 select API は、以下のように定義されています。
int select(int nfds, fd_set *readfds, fd_set *writefds,
       fd_set *exceptfds, struct timeval *timeout);
select の動作は poll の動作と完全に同じではないので、自分のコードを変更する必要があります。 select では、返されるファイル記述子を操作するためのマクロがいくつか提供されますが、その方法は poll の場合と異なります。

コードの変更を回避する別の方法としては、たとえば「fakepoll.h」のような select のラッパを使用することです。ファイル「fakepoll.h」をコードにインクルードするだけで、ライブラリが必要な処理を行ってくれます。「fakepoll.h」の詳細については、sealiesoftware.com/fakepoll.h を参照してください。
注記:fakepoll.h」はサードパーティ製のライブラリであり、アップルのサポート対象外です。
sbrk、brk
brksbrk の関数は、仮想メモリ管理の出現以前から残っている歴史上の珍物です。システム上で存在するとしても、それらを使用することはお薦めしません。
shmget
この API はサポートされていますが、その使用は推奨されません。 shmget に割り当てられているメモリブロックは限られています。複数のアプリケーションが shmget を使用すると、この制限が変更され、ほかのアプリケーションに問題が生じることがあります。メモリに対するファイルマッピングには mmap の使用をお薦めします。
swapon、swapoff
この API は Mac OS X ではサポートされていません。Mac OS X においてこれに相当するのは、macx_swaponmacx_swapoff です。
wordexp、wordfrees
Mac OS X でサポートされていません。

ユーティリティ

ldd
ldd コマンドは Mac OS X では利用できません。ただし、コマンド otool -L を使用して ldd と同じ機能を得ることができます。otool コマンドは、オブジェクトファイルまたはライブラリの指定された部分を表示します。オプション -L は、オブジェクトファイルによって使用されている共有ライブラリの名前とバージョン番号を表示します。利用可能なすべてのオプションについては、マニュアルの otool のページを参照してください。
lsmod
lsmod は Mac OS X では利用できませんが、同様の機能を提供するほかのコマンドが存在します。単に情報が必要なだけの場合は、kmodstat が最も役に立ちます。 kmodstat は、現在ロードされているドライバおよびほかのカーネル拡張についての統計情報を出力します。関連するほかの関数を以下に示します。
kmodload
デバイスドライバおよびほかのカーネル拡張用のカーネルモジュールをロードします。
kmodunload
デバイスドライバおよびほかのカーネル拡張用のカーネルモジュールをアンロードします。
kmodsyms
リモートデバッグ用に静的にリンクされたシンボルファイルを作成します。

参考文献

アップルのデベロッパ関連ドキュメント

サードパーティによる移植に関するドキュメント

URL

  1. Mac OS X: (www.apple.com/macosx/)
  2. UNIX: (www.unix.org/)
  3. Inside Mac OS X: System Overview: (developer.apple.com/techpubs/macosx/Essentials/devessentials.html)
  4. OpenDarwin: (www.opendarwin.org)
  5. Fink: (fink.sourceforge.net)
  6. アップルのデベロッパ Web サイト: (developer.apple.com/ja)
  7. Mac OS X Developer Tools: (developer.apple.com/tools/macosxtools.html)
  8. unix-porting: (lists.apple.com/mailman/listinfo/unix-porting)
  9. darwin-development: (lists.apple.com/mailman/listinfo/darwin-development)
  10. darwinos-users: (lists.apple.com/mailman/listinfo/darwinos-users)
  11. アーカイブ: (search.lists.apple.com)
  12. オライリー社の Mac DevCenter: (www.macdevcenter.com)
  13. Stepwise: (www.stepwise.com)
  14. Berkeley Software Distributions (BSD): (www.bsd.org)
  15. FreeBSD: (www.freebsd.org)
  16. NetBSD: (www.netbsd.org)
  17. カーネギーメロン大学の Mach Project: (www-2.cs.cmu.edu/afs/cs.cmu.edu/project/mach/public/www/mach.html)
  18. Darwin: (developer.apple.com/darwin)
  19. Quartz Extreme: (developer.apple.com/quartz)
  20. OpenGL : (developer.apple.com/opengl)
  21. QuickTime: (developer.apple.com/quicktime)
  22. International Technologies: (developer.apple.com/intl)
  23. CUPS: (developer.apple.com/printing)
  24. Project Builder: (developer.apple.com/tools/projectbuilder)
  25. Interface Builder: (developer.apple.com/tools/interfacebuilder)
  26. アップルの開発ツール: (developer.apple.com/tools)
  27. Linux: (www.kernel.org)
  28. Solaris: (wwws.sun.com/software/solaris)
  29. Mac OS X Threading Architectures: (developer.apple.com/ja/technotes/tn2028.html)
  30. Unicode: (www.unicode.org/standard/WhatIsUnicode.html)
  31. Unicode Consortium: (www.unicode.org)
  32. CoreFoundation StringServices: (developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/index.html)
  33. Creating a Device Driver With Project Builder: (developer.apple.com/documentation/DeviceDrivers/)
  34. Core Audio デベロッパドキュメント: (developer.apple.com/audio/coreaudio.html)
  35. QuickTime Developer Documentation: (developer.apple.com/documentation/quicktime/quicktime.html)
  36. Security Services: (developer.apple.com/security)
  37. Authorization Services: (developer.apple.com/documentation/Security/Conceptual/authorization_concepts/index.html)
  38. 認証用サンプルコード: (developer.apple.com/samplecode/Sample_Code/Security/AuthSample.htm)
  39. Working With Multiprocessing Services(テクニカルノート 1071): (developer.apple.com/ja/technotes/tn1071.html)
  40. CoreFoundation: (developer.apple.com/documentation/CoreFoundation/Reference)
  41. CFString Reference: (developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/index.html)
  42. CFBundleCopyLocalizedString: (developer.apple.com/documentation/CoreFoundation/Reference/CFStringRef/index.html)
  43. GNU C Preprocessor (developer.apple.com/documentation/DeveloperTools/gcc-3.3/cpp/index.html)